﻿using System;
using MathService.DSP.Fourier;

namespace MathService.DSP.Signals
{
    public class SpectrumSignal : DigitalSignal
    {
        /* -------------------------------------------------------------------------------------------- */

        private readonly double[] f_ImValues;

        /* -------------------------------------------------------------------------------------------- */

        public new Complex this[int i]
        {
            get { return new Complex(base[i], f_ImValues[i]); }
            set { base[i] = value.Re; f_ImValues[i] = value.Im; }
        }

        public new Complex this[double x]
        {
            get
            {
                var lv_X = (x - x0) / dx;
                return new Complex(base[x],
                    (lv_X >= 0 && lv_X <= SamplesCount) ? ValueInterpolator[lv_X, f_ImValues] : 0);
            }
            set
            {
                var lv_X = (x - x0) / dx;
                base[x] = value.Re;
                if(lv_X >= 0 && lv_X < SamplesCount)
                    ValueInterpolator[lv_X, f_ImValues] = value.Im;
            }
        }

        /* -------------------------------------------------------------------------------------------- */

        public SpectrumSignal(double f0, Complex[] Spectrum)
            : base(f0, Spectrum.Length)
        {
			f_ImValues = new double[Spectrum.Length];
			var i_Length = Spectrum.Length;
        	for(var i = 0; i < i_Length; i++)
            {
                base[i] = Spectrum[i].Re;
                f_ImValues[i] = Spectrum[i].Im;
            }
        }

        public SpectrumSignal(double f0, double[] Re, double[] Im)
            : base(f0, Re)
        {
            f_ImValues = new double[Im.Length];
            Array.Copy(Im, f_ImValues, Im.Length);
        }

        public SpectrumSignal(DigitalSignal Re, DigitalSignal Im) : this(Re.dx, Re, Im) { }

        /* -------------------------------------------------------------------------------------------- */

        public DigitalSignal ToRe()
        {
            return new DigitalSignal(dx, x0, this);
        }

        public DigitalSignal ToIm()
        {
            return new DigitalSignal(dx, x0, f_ImValues);
        }

        public DigitalSignal ToAbs()
        {
            var lv_Abs = new double[SamplesCount];
        	var i_Length = lv_Abs.Length;
        	for(var i = 0; i < i_Length; i++)
            {
                var lv_Re = base[i];
                var lv_Im = f_ImValues[i];
                lv_Abs[i] = Math.Sqrt(lv_Re * lv_Re + lv_Im * lv_Im);
            }
            return new DigitalSignal(dx, x0, lv_Abs);
        }

        public DigitalSignal ToArg()
        {
            var lv_Arg = new double[SamplesCount];
        	var i_Length = lv_Arg.Length;
        	for(var i = 0; i < i_Length; i++)
                lv_Arg[i] = Math.Atan2(f_ImValues[i], base[i]);
            return new DigitalSignal(dx, x0, lv_Arg);
        }

        public new Complex[] Samples
        {
            get { return Complex.CreateArray(base.Samples, f_ImValues); }
        }

        /* -------------------------------------------------------------------------------------------- */

        public DigitalSignal GetRealSignal()
        {
            return new DigitalSignal(Length.GetInverse(), Samples.FastFurierInverse().ToRe());
        }

        public DigitalSignal GetAbsSignal()
        {
            return new DigitalSignal(Length.GetInverse(), Samples.FastFurierInverse().ToAbs());
        }
    }
}
